package com.dapeis.api.utils;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.CachingConfigurer;
import com.ag.core.exception.TokenIllegalException;
import com.ag.core.utils.AgAssert;
import com.ag.module.common.api.domain.vo.KVObj;
import com.ag.utils.AlgorithmEnum;
import com.ag.utils.AlgorithmUtils;
import com.ag.utils.DictionarySettingUtils;
import com.ag.utils.NumberUtils;
import com.ag.utils.SpringUtils;
import com.ag.utils.json.GsonUtils;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

/**
 * 
 * Title:ApiTokenUtils.java ApiTokenUtils Description:
 * 
 * @author yuanyong
 * @date 2016年11月13日 上午2:54:45 Email: hzyuanyong@126.com
 *
 */
public class ApiTokenUtils {
    protected final static Logger logger = LoggerFactory
	    .getLogger(ApiTokenUtils.class);

    public static final String USER_REDIS_PRE_KEY = "user_api_token_";// 用户ID对应的token

    public static final String COLLOCATION_REDIS_PRE_KEY = "collocation_api_token_"; // 搭配师ID对应的token

    static JsonParser jsonParser = new JsonParser();

    /**
     * 生成 token
     * 
     * @param userId
     * @param tokenKey
     * @param deviceId
     * @return
     * @throws Exception
     */
    public static String generateTokenAndSaveRedis(HttpServletRequest request,
	    Integer pk, String redisPreKey, String tokenKey, String deviceId) {
	Cache cache = getCache();

	String userPK = redisPreKey + "pk_" + pk;
	String otherSameUserToken = cache.get(userPK, String.class);
	KVObj token = generateToken(pk, deviceId, tokenKey);
	String userTokenPK = redisPreKey + token.k;

	if (StringUtils.isNotBlank(otherSameUserToken)) {// 这个用户之前有token登陆
	    String deleteToken = redisPreKey + otherSameUserToken;
	    logger.warn("删除之前的用户的token:" + deleteToken);
	    cache.evict(deleteToken);

	    // NoticePushService noticePushService =
	    // SpringUtils.getBean(NoticePushService.class);
	    // logger.info("发送信息给之前的登陆用户“被T的通知”,pk:{},redisPreKey:{}", pk,
	    // redisPreKey);

	}

	cache.put(userTokenPK, token.v.toString());
	cache.put(userPK, token.k.toString());

	return token.k;
    }

    private static Cache getCache() {
	CachingConfigurer cachingConfigurer = SpringUtils
		.getBean(CachingConfigurer.class);
	Cache cache = cachingConfigurer.cacheManager().getCache("token");
	return cache;
    }

    public static void setTokenExpiration(HttpServletRequest request,
	    String redisPreKey, Integer pk) {
	String token = request.getHeader("token");

	Cache cache = getCache();
	cache.evict(redisPreKey + token);

	// StringRedisTemplate stringRedisTemplate =
	// SpringUtils.getBean(StringRedisTemplate.class);
	// stringRedisTemplate.delete(redisPreKey + token);

	if (NumberUtils.isValid(pk)) {
	    logger.warn("删除token的主键的redis:" + (redisPreKey + "pk_" + pk));
	    // stringRedisTemplate.delete(redisPreKey + "pk_" + pk);

	    cache.evict(redisPreKey + "pk_" + pk);
	}
	logger.info("setTokenExpiration: {}", redisPreKey + token);
    }

    // 创建token
    private static KVObj generateToken(Integer pk, String deviceId,
	    String tokenKey) {
	JsonObject json = new JsonObject();
	// 主键
	json.addProperty("pk", pk);
	// 设备编号
	json.addProperty("deviceId", deviceId);
	// 创建时间
	json.addProperty("ct", System.currentTimeMillis() / 1000);
	String tokenSource = json.toString();

	try {
	    String tokenEncry = AlgorithmUtils.encode(
		    AlgorithmUtils.encrypt(tokenSource, tokenKey),
		    AlgorithmEnum.MD5);
	    return new KVObj(tokenEncry, tokenSource + "||" + pk);
	} catch (Exception e) {
	    e.printStackTrace();
	    logger.error("生成token失败:{},将使用base64加密!", e.getLocalizedMessage());
	}

	return new KVObj(AlgorithmUtils.enBase64(tokenSource), tokenSource
		+ "||" + pk);
    }

    private static JsonObject getJsonFromRedis(String token, String redisPreKey) {
	Cache cache = getCache();

	String string = cache.get(redisPreKey + token, String.class);

	if (StringUtils.isBlank(string)) {
	    return null;
	}

	string = string.substring(0, string.lastIndexOf("||"));
	try {
	    JsonElement jsonElement = jsonParser.parse(string);
	    AgAssert.isTrue(jsonElement.isJsonObject(),
		    TokenIllegalException.class, "非法token json串.");

	    return jsonElement.getAsJsonObject();
	} catch (Exception e) {
	    e.printStackTrace();
	}

	return null;
    }

    /**
     * 
     * 验证token并且或者对应的pk值
     * 
     * @param request
     *            取token、deviceId与缓存中的验证
     * @param redisPreKey
     * @return
     */
    public static Integer tokenCheckAndGet(HttpServletRequest request,
	    String redisPreKey) {
	// BaseController.printHeader(request);
	// 获取请求的token
	String token = request.getHeader("token");
	String deviceId = request.getHeader("deviceId");
	// 如果token或者deviceId为空 则返回0
	if (StringUtils.isBlank(token)) {
	    return NumberUtils.DEFAULT_VALUE;
	}
	// 从redis中获取json串，如果获取不到，则返回0
	JsonObject json = getJsonFromRedis(token, redisPreKey);
	if (json == null) {
	    return NumberUtils.DEFAULT_VALUE;
	}

	// token获取的json串中，deviceId和请求头中的设备ID不同时，抛出异常
	String tokenDeviceId = GsonUtils.getString(json, "deviceId");

	AgAssert.isTrue(tokenDeviceId.equals(deviceId),
		TokenIllegalException.class, "token 验证时设备不匹配");

	// token有效期
	long timeDiff = (System.currentTimeMillis() / 1000)
		- GsonUtils.getLong(json, "ct");
	// 如果设置参数，则返回设置值，否则返回默认值7*24
	int hour = DictionarySettingUtils.getParameterValueWithDefaultInt(
		"terminal.token.expire", 24 * 365 * 5);
	long defaultExpireTime = hour * 60 * 60;
	// 当前时间和创建时间差值超过超时时间
	if (timeDiff > defaultExpireTime) {// token 过期不处理
	    logger.debug("token 过期不处理.");
	    return NumberUtils.DEFAULT_VALUE;
	} else {
	    return GsonUtils.getInt(json, "pk");
	}
    }
}